//use rlgo::mpt::*;

pub mod long_key {
    use rand::distributions::{Distribution, Standard};
    use rand::Rng;
    use rlgo::radix::*;
    use rlgo::skiplist::long_key::*;

    fn gen_sample<T>(total: u32) -> Vec<Box<[T]>>
    where
        T: Clone + Eq + PartialEq + Ord + PartialOrd,
        Standard: Distribution<T>,
    {
        let mut rng = rand::thread_rng();
        let mut sample = vec![];
        let mut v;

        for _ in 0..total {
            v = vec![];
            (0..256).for_each(|_| v.push(rng.gen::<T>()));
            sample.push(v.into_boxed_slice());
        }

        sample.sort();
        sample.dedup();
        sample
    }

    fn hashmap<T>(sample: &[Box<[T]>])
    where
        T: Clone + Eq + PartialEq + Ord + PartialOrd + std::hash::Hash,
    {
        let mut hm = std::collections::HashMap::new();
        sample.iter().cloned().for_each(|i| {
            hm.insert(i, ()).is_none();
        });
        sample.iter().cloned().for_each(|i| {
            hm.get(&i).unwrap();
            hm.remove(&i).unwrap();
        });
    }

    fn radix<T>(sample: &[Box<[T]>])
    where
        T: Clone + Eq + PartialEq + Ord + PartialOrd,
    {
        let mut radix = Radix::new();
        sample.iter().cloned().for_each(|i| {
            radix.put(i, ()).is_ok();
        });
        sample.iter().cloned().for_each(|i| {
            radix.get_x(&i[..]).unwrap();
            radix.del_x(&i[..]).unwrap();
        });
    }

    fn skiplist<T>(sample: &[Box<[T]>])
    where
        T: Clone + Eq + PartialEq + Ord + PartialOrd,
    {
        let mut sl = SkipList::default();
        sample.iter().for_each(|i| {
            sl.put(i, ()).is_ok();
        });
        sample.iter().for_each(|i| {
            sl.get(&i).unwrap();
            sl.del(&i).unwrap();
        });
    }

    pub fn go() {
        let sample;
        if cfg!(debug_assertions) {
            sample = gen_sample::<i32>(1000);
            println!("\n\x1b[31;01m** Long Key Benchmark <1000 items> **\x1b[00m");
        } else {
            sample = gen_sample::<i32>(10_0000);
            println!("\n\x1b[31;01m** Long Key Benchmark <10_0000 items> **\x1b[00m");
        };

        let now = std::time::Instant::now();
        hashmap(&sample);
        println!("\x1b[31;01mHashMap\x1b[00m: {:?}", now.elapsed());

        let now = std::time::Instant::now();
        radix(&sample);
        println!("\x1b[31;01mRadix\x1b[00m: {:?}", now.elapsed());

        let now = std::time::Instant::now();
        skiplist(&sample);
        println!("\x1b[31;01mSkipList\x1b[00m: {:?}", now.elapsed());
    }
}

pub mod short_key {
    use rand::distributions::{Distribution, Standard};
    use rand::Rng;
    use rlgo::skiplist::short_key::*;

    fn gen_sample<T>(total: u32) -> Vec<T>
    where
        T: Clone + Eq + PartialEq + Ord + PartialOrd,
        Standard: Distribution<T>,
    {
        let mut rng = rand::thread_rng();
        let mut sample = vec![];

        for _ in 0..total {
            sample.push(rng.gen::<T>());
        }

        sample.sort();
        sample.dedup();
        sample
    }

    fn hashmap<T>(sample: &[T])
    where
        T: Clone + Eq + PartialEq + Ord + PartialOrd + std::hash::Hash,
    {
        let mut hm = std::collections::HashMap::new();
        sample.iter().for_each(|i| {
            hm.insert(i, ()).is_none();
        });
        sample.iter().for_each(|i| {
            hm.get(&i).unwrap();
            hm.remove(&i).unwrap();
        });
    }

    fn skiplist<T>(sample: &[T])
    where
        T: Clone + Eq + PartialEq + Ord + PartialOrd,
    {
        let mut sl = SkipList::default();
        sample.iter().for_each(|i| {
            sl.put(i, ()).is_ok();
        });
        sample.iter().for_each(|i| {
            sl.get(i).unwrap();
            sl.del(i).unwrap();
        });
    }

    pub fn go() {
        let sample;
        if cfg!(debug_assertions) {
            sample = gen_sample::<i32>(1000);
            println!("\n\x1b[31;01m** Short Key Benchmark <1000 items> **\x1b[00m");
        } else {
            sample = gen_sample::<i32>(10_0000);
            println!("\n\x1b[31;01m** Short Key Benchmark <10_0000 items> **\x1b[00m");
        };

        let now = std::time::Instant::now();
        hashmap(&sample);
        println!("\x1b[31;01mHashMap\x1b[00m: {:?}", now.elapsed());

        let now = std::time::Instant::now();
        skiplist(&sample);
        println!("\x1b[31;01mSkipList\x1b[00m: {:?}", now.elapsed());
    }
}

pub fn go() {
    long_key::go();
    short_key::go();
}
